package com.sanri.tools.modules.mock.l7.websocket.server;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sanri.tools.modules.core.exception.ToolException;
import com.sanri.tools.modules.mock.l7.websocket.event.*;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Service;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.net.InetSocketAddress;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
@Slf4j
public class WebsocketServerService implements ApplicationListener<WebsocketEvent>{

    @Autowired
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    /**
     * 启动的服务列表
     */
    private Map<Integer, CustomWebsocketServer> startServerMap = new ConcurrentHashMap<>();

    /**
     * 启动服务
     * @param port
     */
    public void startServer(Integer port, CustomWebsocketServer.OnStart onStart){
        CustomWebsocketServer customWebsocketServer = startServerMap.get(port);
        if (customWebsocketServer == null){
            final InetSocketAddress inetSocketAddress = new InetSocketAddress(port);
            customWebsocketServer = new CustomWebsocketServer(inetSocketAddress);
            customWebsocketServer.start(onStart);
            return;
        }

    }

    public void serverState(Integer port){
        CustomWebsocketServer customWebsocketServer = startServerMap.get(port);
        if(customWebsocketServer == null){
            // 未启动
            return ;
        }
    }

    /**
     * 发送一个文本消息到 websocket
     * @param uri
     * @param message
     * @throws URISyntaxException
     */
    public void sendMessageToClient(Integer port, String clientOrGroup, String message) throws URISyntaxException {
        log.info("发送消息到[{}][{}], 消息为: {}",port, clientOrGroup, message);
        final CustomWebsocketServer customWebsocketServer = startServerMap.get(port);
        if (customWebsocketServer == null){
            startServer(port, websocketServer -> {
                innerSendMessageToClients(websocketServer, message);
            });
        }else {
            innerSendMessageToClients(customWebsocketServer, message);
        }

    }

    private void innerSendMessageToClients(CustomWebsocketServer websocketServer, String message){
        for (WebSocket connection : websocketServer.getConnections()) {
            final InetSocketAddress remoteSocketAddress = connection.getRemoteSocketAddress();
            // 匹配地址是否正确, 通过绑定关系等, 然后往这个地址推送消息
            if (true){
                connection.send(message);
            }
        }
    }

    /**
     * 处理 websocket 消息
     * @param websocketEvent
     */
    public void handleMessage(MessageWebsocketEvent websocketEvent){
        final String message = websocketEvent.getMessage();
        final WebSocket webSocket = (WebSocket) websocketEvent.getSource();
        log.info("收到消息: {}", message);

        final JSONObject jsonObject = JSON.parseObject(message);
        final String path = jsonObject.getString("path");
        final List<HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethodsForMappingName(path);
        for (HandlerMethod handlerMethod : handlerMethods) {
            final Object bean = handlerMethod.getBean();
            // 调用消息实现
            Object invokeMethod = ReflectionUtils.invokeMethod(handlerMethod.getMethod(), bean, message);

            // 先暂时把每个实现的响应都写回去
            webSocket.send(JSON.toJSONString(invokeMethod));
        }
    }

    @Override
    public void onApplicationEvent(WebsocketEvent websocketEvent) {
        final Object source = websocketEvent.getSource();
        if (!(source instanceof WebSocket)){
            return ;
        }
        final WebsocketEvent.MessageType messageType = websocketEvent.messageType();
        switch (messageType){
            case MESSAGE:
                handleMessage((MessageWebsocketEvent)websocketEvent);
                break;
            case CONNECT:
                ConnectWebsocketEvent connectWebsocketEvent = (ConnectWebsocketEvent) websocketEvent;
                final ClientHandshake clientHandshake = (ClientHandshake) connectWebsocketEvent.getHandshakedata();
                log.info("连接:{}",clientHandshake);
                break;
            case CLOSE:
                CloseWebsocketEvent closeWebsocketEvent = (CloseWebsocketEvent) websocketEvent;
                log.error("socket 已经被关闭: {}{}{}", closeWebsocketEvent.getCode(), closeWebsocketEvent.getReason(),closeWebsocketEvent.isRemote());
                break;
            case ERROR:
                ErrorWebsocketEvent errorWebsocketEvent = (ErrorWebsocketEvent) websocketEvent;
                log.error("异常: {}",errorWebsocketEvent.getException());
                break;
        }
    }


}
